package com.xiaohai.wx.weather.service;

import com.gargoylesoftware.htmlunit.CookieManager;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine;
import com.gargoylesoftware.htmlunit.util.Cookie;
import com.xiaohai.wx.weather.dto.User;
import com.xiaohai.wx.weather.message.TextMsgHandler;
import com.xiaohai.wx.weather.util.PropertiesUtil;
import com.xiaohai.wx.weather.util.UrlUtils;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;

@Service("WeixinPlatformAgent")
public class WeixinPlatformAgent {

    private String TOKEN;
    private Map<String, String> cookies;

    private final String HOME_PAGE_URL = "https://mp.weixin.qq.com";
    private final String SEND_MSG_URL = "http://mp.weixin.qq.com/cgi-bin/singlesend?t=ajax-response&lang=zh_CN";


    Logger logger = Logger.getLogger(this.getClass());

    @Autowired
    UserService userService;

    @Autowired
    LocationService locationService;

    @Autowired
    WeatherService weatherService;

    @Autowired
    TextMsgHandler messageHandler;

    public void login() throws Exception {
        String homePageUrl = "https://mp.weixin.qq.com/";

        String loginPageUrl = "https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN";

        String username = PropertiesUtil.getProperty("adminUserName");
        String password = PropertiesUtil.getProperty("adminUserPassword");


        //Connection.Response response = Jsoup.connect(homePageUrl)
        //        .userAgent("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0")
        //        .method(Connection.Method.GET).timeout(0)
        //        .execute();

        Connection.Response response = null;

        for (int i = 0; i < 4; i++) {
            try {
                response = Jsoup.connect(loginPageUrl).ignoreContentType(true)
                        .userAgent("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0")
                        .referrer("https://mp.weixin.qq.com/")
                        .data("username", username)
                        .data("pwd", password)
                        .data("f", "json")
                        .data("imgcode", "")
                                //.cookies(response.cookies())
                        .method(Connection.Method.POST)
                        .timeout(10000) //10 seconds
                        .execute();
                break;
            } catch (IOException e) {
                logger.error("JSOUP login failed: " + i + " time.");
                e.printStackTrace();
                if (i == 3) {
                    throw e;
                }
            }

            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


        String respObject = response.body();
        logger.debug(respObject);

        JSONParser parser = new JSONParser();
        Object obj = parser.parse(respObject);
        String homePage = "";
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            String errCode = String.valueOf(json.get("ErrCode"));
            String retCode = String.valueOf(json.get("Ret"));
            if ("302".equals(retCode) && "0".equals(errCode)) {
                homePage = (String) json.get("ErrMsg");
                TOKEN = UrlUtils.getQueryParam(homePage).get("token");
                homePage = homePageUrl + (homePage.startsWith("/") ? homePage : "/" + homePage);
            } else {
                throw new Exception("Login didn't get correct response!");
            }
        } else {
            throw new FileUploadBase.InvalidContentTypeException("It's not JSON format or the string can't be converted to JSON!");
        }

        //if (StringUtils.isNotBlank(homePage)) {
        //    response = Jsoup.connect(homePage)
        //            .userAgent("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0")
        //            .cookies(response.cookies())
        //            .header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
        //            .method(Connection.Method.GET).timeout(0)
        //             .execute();
        // }
        this.cookies = response.cookies();
    }


    public List<User> getFans() throws Exception {
        List<User> userList = new ArrayList<User>();
        String FANS_URL = "https://mp.weixin.qq.com/cgi-bin/contactmanage?t=user/index&token=${:token}&lang=zh_CN&pagesize=${:pagesize}&pageidx=${:index}&type=0&groupid=0";
        String ReferPage = "https://mp.weixin.qq.com/cgi-bin/settingpage?t=setting/index&action=index&token=${:token}&lang=zh_CN";

        Map<String, String> param = new HashMap<String, String>();
        param.put("token", TOKEN);
        param.put("pagesize", "10");
        param.put("index", "0");
        FANS_URL = UrlUtils.replaceNamedParam(FANS_URL, param);
        ReferPage = UrlUtils.replaceNamedParam(ReferPage, param);

        WebClient wc = new WebClient();
        wc.getBrowserVersion().setUserAgent("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0");

        wc.addRequestHeader("Referer", ReferPage);
        wc.getOptions().setJavaScriptEnabled(true);
        wc.getOptions().setCssEnabled(true);
        wc.setJavaScriptEngine(new JavaScriptEngine(wc));
        wc.getOptions().setThrowExceptionOnScriptError(false);
        wc.getOptions().setThrowExceptionOnFailingStatusCode(false);
        CookieManager cm = new CookieManager();
        cm.setCookiesEnabled(true);
        for (Map.Entry<String, String> cookie : this.cookies.entrySet()) {
            Cookie c = new Cookie("mp.weixin.qq.com", cookie.getKey(), cookie.getValue());
            cm.addCookie(c);
        }
        wc.setCookieManager(cm);
        HtmlPage page = this.readPage(wc, FANS_URL, 3);

        Document document = Jsoup.parse(page.asXml());
        Element elem = document.getElementById("userGroups");
        Elements items = elem.getElementsByAttributeValueContaining("class", "user_info");
        for (Element item : items) {
            User user = new User();
            Element child = item.select("a[data-fakeid][class*=remark_name]").first();
            user.setFakeId(child.attr("data-fakeid"));
            user.setRemarkName(child.text());
            userList.add(user);
        }
        return userList;
    }

    public List<User> matchUser(Map<String, User> matchInfo, List<String> excludes) {

        List<User> returnedUserList = new ArrayList<User>();
        String talkRecordUrl = "https://mp.weixin.qq.com/cgi-bin/singlesendpage?t=message/send&action=index&tofakeid=${:fakeId}&token=${:token}&lang=zh_CN";
        Map<String, String> param = new HashMap<String, String>();
        param.put("token", TOKEN);

        CookieManager cm = new CookieManager();
        cm.setCookiesEnabled(true);
        for (Map.Entry<String, String> cookie : this.cookies.entrySet()) {
            Cookie c = new Cookie("mp.weixin.qq.com", cookie.getKey(), cookie.getValue());
            cm.addCookie(c);
        }

        try {

            List<User> users = getFans();
            users:for (User user : users) {
                if (excludes == null || (excludes != null && !excludes.contains(user.getFakeId()))) {
                    param.put("fakeId", user.getFakeId());
                    String talkRecordUrl2 = UrlUtils.replaceNamedParam(talkRecordUrl, param);

                    WebClient wc = new WebClient();
                    wc.getBrowserVersion().setUserAgent("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0");
                    wc.getOptions().setTimeout(0);
                    wc.addRequestHeader("Referer", HOME_PAGE_URL);
                    wc.getOptions().setJavaScriptEnabled(false);
                    wc.getOptions().setCssEnabled(false);
                    wc.setJavaScriptEngine(new JavaScriptEngine(wc));
                    wc.getOptions().setThrowExceptionOnScriptError(false);
                    wc.getOptions().setThrowExceptionOnFailingStatusCode(false);
                    wc.getOptions().setPopupBlockerEnabled(false);
                    wc.getOptions().setPrintContentOnFailingStatusCode(false);

                    wc.setCookieManager(cm);
                    HtmlPage page = this.readPage(wc, talkRecordUrl2, 3);

                    Document document = Jsoup.parse(page.asXml());
                    Elements scripts = document.getElementsByTag("script").select(":not([src])");
//                    Elements elems = document.select("div.user_info>span[data-fakeid=2391242664].avatar");
                    for (Element elem : scripts) {
                        String resp = elem.data();
                        if (!resp.contains("wx.cgiData")) {
                            continue;
                        }
                        resp = resp.substring("wx.cgiData".length() + 1);
                        int startIdx=resp.indexOf("{");
                        int endIdx=resp.lastIndexOf("wx.cgiData");
                        resp=resp.substring(startIdx,endIdx).trim();
                        resp=resp.substring(0,resp.length()-1);

                        JSONParser parser=new JSONParser();
                        JSONObject json= (JSONObject) parser.parse(resp);
                        JSONArray msglst= (JSONArray) ((JSONObject)json.get("msg_items")).get("msg_item");

                        Iterator it=msglst.iterator();
                        while (it.hasNext()){
                            JSONObject detail= (JSONObject) it.next();
                            String msg= (String) detail.get("content");
                            if(!"2391242664".equals(detail.get("fakeid"))){
                                continue;
                            }
                            int index = -1;
                            if (StringUtils.isNotBlank(msg) && (index = msg.indexOf("例如: ")) != -1) {
                                msg = msg.substring(index + 4);
                                int end = msg.indexOf(".");
                                if (end <= 0)
                                    continue;
                                String key = msg.substring(0, end);
                                User userInDB = matchInfo.get(key.trim());
                                if(userInDB != null){
                                	userInDB.setFakeId(user.getFakeId());
                                    userInDB.setRemarkName(user.getRemarkName());
                                    returnedUserList.add(userInDB);
                                    break users;
                                }
                            }
                        }
                    }
                }
            }


        } catch (Exception e) {
            logger.error("matchUser error", e);
        }

        return returnedUserList;
    }


    private HtmlPage readPage(WebClient client, String url, int retryCount) throws Exception {

        Exception resultE = new Exception("WebClient can't open page at url: " + url);

        for (int i = 0; i < retryCount; i++) {

            try {
                HtmlPage page = client.getPage(url);
                return page;
            } catch (IOException e) {
                e.printStackTrace();
                resultE = e;
            }

            try {
                Thread.sleep(10000); //sleep for 10 seconds
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }

        throw resultE;
    }

    public void sendMsgToSingleUser(String content, String fakeId)
            throws IOException {

        HashMap<String, String> map = new HashMap<String, String>();
        map.put("tofakeid", fakeId);
        map.put("content", content);
        map.put("error", "false");
        map.put("token", TOKEN);
        map.put("type", "1");
        map.put("imgcode", "");
        map.put("t", "ajax-response");

        map.put("random", String.valueOf(Math.random()));
        String referrerUrl = "https://mp.weixin.qq.com/cgi-bin/singlesendpage?t=message/send&action=index&tofakeid=${:tofakeid}&token=${:token}&lang=zh_CN";
        Document document = Jsoup.connect(SEND_MSG_URL).referrer(referrerUrl).ignoreContentType(true)
                .data(map).cookies(this.cookies).post();
        Element body = document.body();
        logger.debug("send MSG response: " + body.text());
    }


    public static void main(String[] args) throws Exception {


        WeixinPlatformAgent service = new WeixinPlatformAgent();
        service.login();

        User questionUser = new User();
        questionUser.setMapKey("山东,河南,河北");
        Map<String, User> userMap = new HashMap<String, User>();
        userMap.put("山东,河南,河北", questionUser);
        List<String> excludes = new ArrayList<String>();
        //excludes.add("714064426");
        List<User> updatedUserList = service.matchUser(userMap, excludes);
        System.out.println(updatedUserList.get(0).toString());
        

        /*
        List<WeixinUser> userList = service.getFans();
        for (WeixinUser user : userList) {
            System.out.println(user.toString());
        }

        service.sendMsgToSingleUser("test", "2158311300");*/
    }

}